/*********************************************************************************
 * Software License Agreement (BSD License)
 * Copyright (c) 2012, Carlos D. Correa (info@ngraph.org)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of netzen nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************************/
/***************************************************************************
 *
 * Clustering Coefficient
 * 
 *
 * Copyright (C) 2009 by Tarik Crnovrsanin, UC Davis
 *
 **************************************************************************/

#include "timing.h"

#include "node.h"
#include "clusteringCoefficient.h"

#include <utility>                   // for std::pair
#include <algorithm>                 // for std::for_each
#include <climits>
#include <assert.h>


  
ClusteringCoefficient::ClusteringCoefficient(Controller *controller):AnalysisTool("Clustering","ClusteringCoefficient",controller) {
  setPropertyStringList("Edge Weight", "Default", "edge");
  setPropertyString("Result", getName());
}

void ClusteringCoefficient::compute() {
  assert(controller);
  // TO DO: set up these two via UI
  Graph *g = controller->getGraph("graph");
  bool derivs =  this->getPropertyBool("Derivatives");

  string resultProp = getPropertyString("Result");
  string resultDerivs = resultProp + ".Derivative";

  compute(g->nodes, derivs);
  controller->addDataProperty("node", resultProp, PROPERTY_FLOAT);
  g->computeNodeMinMaxFloat(resultProp);
  if(derivs) {
    controller->addDataProperty("edge",resultDerivs, PROPERTY_FLOAT);
    g->computeEdgeMinMaxFloat(resultDerivs);
  }
  
 controller->exportFloat(g,"coeff.float", resultProp.c_str());
  if(derivs)
   controller->exportImplicitEdgeFloat(g, "coeffderivas.float", resultDerivs.c_str());
}

 
int ClusteringCoefficient::compute(vector<Node*> &nodes, bool /*needDerivs*/) {
  timestamp t1 = now();
  int n = nodes.size();
  vector<float> coeff;
  vector<float> coeff2;
  
  string resultProp = getPropertyString("Result");
  string resultDerivs = resultProp + ".Derivative";
  string edgeProperty = getPropertyString("Edge Weight");
  if(listener) listener->setProgress(0);
  for(int i=0;i<n;i++) {
    nodes[i]->createImplicitEdges(n, nodes);
  }

  int id1,id2,comb = 0;
  float count;
  for(int i=0;i<n;i++) {
    count =0;
    for(unsigned int k=0;k<nodes[i]->edges.size();k++) {
      id1 = nodes[i]->edges[k]->getNode1()->getPropertyInt("NodeId");
      for(unsigned int j = 0; j < nodes[i]->edges.size();j++){
        int size = nodes[i]->edges[j]->getNode1()->edges.size();
         for(int a = 0; a < size; a++){
            id2 = nodes[i]->edges[j]->getNode1()->edges[a]->getNode1()->getPropertyInt("NodeId");
          if(k != j && id1 == id2){
            count+=1;
            break;
          }
        }
      }
    }
    printf("comb:%d count:%f\n",comb,count);
    comb = nodes[i]->edges.size()*(nodes[i]->edges.size()-1);
    if(comb == 0)
      coeff.push_back(0);
    else
      coeff.push_back(count/comb);
  }

  for(unsigned int i = 0; i < coeff.size(); i++){
    nodes[i]->setPropertyFloat(resultProp,coeff[i]);
   }
/*
if(needDerivs) {
 for(int b=0;b<n;b++) {
   if(listener) listener->setProgress((float) b/(float) n);
   id0 = nodes[b]->getPropertyInt("NodeId");
   for(int i=0;i<n;i++) {
     count = 0;
     count2 = 0;
     for(int k=0;k<nodes[i]->edges.size();k++) {
       id1 = nodes[i]->edges[k]->getNode1()->getPropertyInt("NodeId");
       if(id1 == id0){
         count2++;
         continue;
        }
       for(int j = 0; j < nodes[i]->edges.size();j++){
         int size = nodes[i]->edges[j]->getNode1()->edges.size();
         for(int a = 0; a < size; a++){
             id2 = nodes[i]->edges[j]->getNode1()->edges[a]->getNode1()->getPropertyInt("NodeId");
           if(id2 == id0){
            continue;
           }
           if(k != j && id1 == id2){
             count+=1;
             break;
           }//if
         }// for a
       }//for j
     }//for k
     comb = (nodes[i]->edges.size()-count2)*(nodes[i]->edges.size()-count2-1);
    if(comb == 0)
      coeff2.push_back(0);
    else
      coeff2.push_back(count/comb);
   }//for i
    for(int m = 0; m < n; m++){ 
    nodes[b]->getImplicitEdge(m)->setPropertyFloat(resultDerivs, coeff[m] - coeff2[m]);
	  if(nodes[b]->hasEdge(m)) {
	    nodes[b]->getEdge(m)->setPropertyFloat(resultDerivs, coeff[m] - coeff2[m]);
	  }//if
    }//for m
   coeff2.clear();
 }//for b
}//needDerivs*/

  timestamp t3 = now();
  if(listener) listener->done();
//   printf("[CLOSENESS] Time  %f sec\n", t2 - t1);
//   printf("[CLOSENESS DERIVS] Time  %f sec\n", t3 - t2);
  return 1;
}


